package com.ruibang.glass.quality.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.ruibang.glass.common.constants.RedisKey;
import com.ruibang.glass.quality.constant.Constants;
import com.ruibang.glass.quality.constant.QualityErrorCode;
import com.ruibang.glass.quality.domain.req.SL01QualityMonitorReq;
import com.ruibang.glass.quality.domain.resp.*;
import com.ruibang.glass.quality.mapper.SL01QualityMonitorMapper;
import com.ruibang.glass.quality.service.SL01QualityMonitorService;
import com.teaming.cloud.framework2.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author: songJinKang
 * @CreateTime: 2024-05-24  10:48
 * @Description: TODO
 * @Version: 1.0
 */
@Slf4j
@Service
public class SL01QualityMonitorServiceImpl implements SL01QualityMonitorService {

    @Autowired
    @Qualifier("myRedisTemplate")
    private RedisTemplate<String, Object> redisTemplate;


    @Autowired
    private SL01QualityMonitorMapper sl01QualityMonitorMapper;


    /**
     * 面复检
     *
     * @param sl01QualityMonitorReq
     * @return
     */
    @Override
    public SL01QualityMonitorResp queryFreDefect(SL01QualityMonitorReq sl01QualityMonitorReq) {
        SL01QualityMonitorResp sl01QualityMonitorResp = new SL01QualityMonitorResp();
        List<DefectDetailResp> defectDetailResp = sl01QualityMonitorMapper.faceInspect(sl01QualityMonitorReq);
        if (CollectionUtils.isNotEmpty(defectDetailResp)) {
            //缺陷数据
            Map<String, List<DefectDetailResp>> dataMap = defectDetailResp.stream().collect(Collectors.groupingBy(DefectDetailResp::getDefectName));
            sl01QualityMonitorResp.setFreDefectData(dataMap);
            //统计数据
            FreStatisticsData freStatisticsData = statisticsFreData(defectDetailResp);
            sl01QualityMonitorResp.setFreStatisticsData(freStatisticsData);
        }
        return sl01QualityMonitorResp;
    }

    /**
     * 颗粒检
     *
     * @param sl01QualityMonitorReq
     * @return
     */
    @Override
    public SL01QualityMonitorResp queryParticleDefect(SL01QualityMonitorReq sl01QualityMonitorReq) {
        SL01QualityMonitorResp sl01QualityMonitorResp = new SL01QualityMonitorResp();
        List<ParticlePlotData> particlePlotData = sl01QualityMonitorMapper.particleDetect(sl01QualityMonitorReq);
        if (CollectionUtils.isNotEmpty(particlePlotData)) {
            //统计数据
            ColdPointLineChartResp coldPointLineChartResp = statisticMjData(particlePlotData);
            sl01QualityMonitorResp.setParticlePlotsStatisticData(coldPointLineChartResp);
            //缺陷数据
            List<ParticlePlot> data = new ArrayList<>();
            Map<String, List<ParticlePlotData>> particlePlotDataMap = particlePlotData.stream().collect(Collectors.groupingBy(ParticlePlotData::getDefectName));
            particlePlotDataMap.forEach((k, v) -> {
                ParticlePlot particlePlot = new ParticlePlot();
                particlePlot.setParticlePlotData(v.stream().sorted(Comparator.comparing(ParticlePlotData::getStartTime)).collect(Collectors.toList()));
                particlePlot.setDefectName(k);
                data.add(particlePlot);
            });
            sl01QualityMonitorResp.setParticlePlots(data);
        }
        return sl01QualityMonitorResp;
    }

    @Override
    public void freDefectConfig(List<FreDefectConfig> defectConfig) {
        if (CollectionUtils.isNotEmpty(defectConfig)) {
            redisTemplate.delete(RedisKey.FRE_DEFECT_CONFIG);
            redisTemplate.opsForList().rightPushAll(RedisKey.FRE_DEFECT_CONFIG, defectConfig.toArray());
        }
    }

    @Override
    public List<FreDefectConfig> getFreDefectConfig() {
        List<Object> freDefectConfigObjList = redisTemplate.opsForList().range(RedisKey.FRE_DEFECT_CONFIG, 0, -1);
        if (CollectionUtils.isNotEmpty(freDefectConfigObjList)) {
            List<FreDefectConfig> data = new ArrayList<>();
            for (Object obj : freDefectConfigObjList) {
                data.add((FreDefectConfig) obj);
            }
            return data;
        }
        return Collections.emptyList();
    }


    /**
     * @Description: 统计面复检
     * @version v1.0
     * @author songJinKang
     * @date 2024-05-24 16:20
     */
    private FreStatisticsData statisticsFreData(List<DefectDetailResp> defectDetailResp) {
        FreStatisticsData freStatisticsData = new FreStatisticsData();
        if (CollectionUtils.isNotEmpty(defectDetailResp)) {
            //面复检缺陷配置信息
            List<FreDefectConfig> freDefectConfigList = this.getFreDefectConfig();
            if (CollectionUtils.isNotEmpty(freDefectConfigList)) {
                //根据缺陷名称分组
                Map<String, List<DefectDetailResp>> defectNameDataMap = defectDetailResp.stream().collect(Collectors.groupingBy(DefectDetailResp::getDefectName));
                //结果集
                Map<String, Long> map_0 = new LinkedHashMap<>();
                Map<String, Long> map_1_2 = new LinkedHashMap<>();
                Map<String, Long> map_3_8 = new LinkedHashMap<>();
                Map<String, Long> map_9_10 = new LinkedHashMap<>();
                for (FreDefectConfig freDefectConfig : freDefectConfigList) {
                    if (freDefectConfig != null) {
                        //根据规则统计
                        long count_0 = 0;
                        long count_1_2 = 0;
                        long count_3_8 = 0;
                        long count_9_10 = 0;
                        for (String ruleDefectName : freDefectConfig.getDefectType()) {
                            List<DefectDetailResp> defectData = defectNameDataMap.get(ruleDefectName);
                            if (CollectionUtils.isNotEmpty(defectData)) {
                                //统计0层
                                count_0 += defectData.stream().filter(e -> e.getTiltedDiv() == 0).count();
                                //统计1-2层
                                count_1_2 += defectData.stream().filter(e -> e.getTiltedDiv() >= 1 && e.getTiltedDiv() <= 2).count();
                                //统计3-8层
                                count_3_8 += defectData.stream().filter(e -> e.getTiltedDiv() >= 3 && e.getTiltedDiv() <= 8).count();
                                //统计9-10层
                                count_9_10 += defectData.stream().filter(e -> e.getTiltedDiv() >= 9 && e.getTiltedDiv() <= 10).count();
                            }
                        }
                        //汇总保存
                        map_0.put(freDefectConfig.getItem(), count_0);
                        map_1_2.put(freDefectConfig.getItem(), count_1_2);
                        map_3_8.put(freDefectConfig.getItem(), count_3_8);
                        map_9_10.put(freDefectConfig.getItem(), count_9_10);
                    }

                }
                freStatisticsData.setData1(map_0);
                freStatisticsData.setData2(map_1_2);
                freStatisticsData.setData3(map_3_8);
                freStatisticsData.setData4(map_9_10);
                freStatisticsData.setGlassNumData(defectDetailResp.stream().map(DefectDetailResp::getGlassId).distinct().count());
            } else {
                throw new ServiceException(QualityErrorCode.PLEASE_CONFIGURE_FRE_RULE.getCode(), QualityErrorCode.PLEASE_CONFIGURE_FRE_RULE.getMsg());
            }
        }
        return freStatisticsData;
    }


    /**
     * @Description: 统计颗粒检数据
     * @version v1.0
     * @author songJinKang
     * @date 2023-12-07 18:13
     */
    private ColdPointLineChartResp statisticMjData(List<ParticlePlotData> particlePlotData) {
        ColdPointLineChartResp coldPointLineChartResp = new ColdPointLineChartResp();
        if (CollectionUtils.isNotEmpty(particlePlotData)) {
            List<String> glassIds = new ArrayList<>();
            List<Integer> s = new ArrayList<>();
            List<Integer> m = new ArrayList<>();
            List<Integer> l = new ArrayList<>();
            List<Integer> ol = new ArrayList<>();
            List<Integer> sb = new ArrayList<>();
            List<Integer> mb = new ArrayList<>();
            List<Integer> lb = new ArrayList<>();
            List<Integer> olb = new ArrayList<>();

            Set<String> sGlassNum = new HashSet<>();
            Set<String> mGlassNum = new HashSet<>();
            Set<String> lGlassNum = new HashSet<>();
            Set<String> olGlassNum = new HashSet<>();
            Set<String> sbGlassNum = new HashSet<>();
            Set<String> mbGlassNum = new HashSet<>();
            Set<String> lbGlassNum = new HashSet<>();
            Set<String> olbGlassNum = new HashSet<>();

            Map<String, List<ParticlePlotData>> particlePlotDataMap = particlePlotData.stream().collect(Collectors.groupingBy(ParticlePlotData::getGlassId));

            for (String key : particlePlotDataMap.keySet()) {
                glassIds.add(key);
                List<ParticlePlotData> defectData = particlePlotDataMap.get(key);
                Map<String, List<ParticlePlotData>> defectDataMap = defectData.stream().collect(Collectors.groupingBy(ParticlePlotData::getDefectName));
                Set<String> defectNames = defectDataMap.keySet();
                List<String> glassPointDefectList = Constants.GLASS_POINT_DEFECT_LIST;
                List<String> distinctNames = Stream.concat(defectNames.stream(), glassPointDefectList.stream()).collect(Collectors.groupingBy(Function.identity(), Collectors.counting())).entrySet().stream().filter(e -> e.getValue() == 1).map(Map.Entry::getKey).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(distinctNames)) {
                    for (String distinctName : distinctNames) {
                        defectDataMap.put(distinctName, Collections.emptyList());
                    }
                }

                defectDataMap.forEach((defectName, totalData) -> {
                    int size = totalData.size();
                    //统计缺陷数量与玻璃片数
                    switch (defectName) {
                        case Constants.GLASS_POINT_DEFECT_S: {
                            //统计缺陷数
                            s.add(size);
                            //统计玻璃片数
                            sGlassNum.addAll(totalData.stream().map(ParticlePlotData::getGlassId).collect(Collectors.toList()));
                            break;
                        }
                        case Constants.GLASS_POINT_DEFECT_M: {
                            //统计缺陷数
                            m.add(totalData.size());
                            //统计玻璃片数
                            mGlassNum.addAll(totalData.stream().map(ParticlePlotData::getGlassId).collect(Collectors.toList()));
                            break;
                        }
                        case Constants.GLASS_POINT_DEFECT_L: {
                            //统计缺陷数
                            l.add(totalData.size());
                            //统计玻璃片数
                            lGlassNum.addAll(totalData.stream().map(ParticlePlotData::getGlassId).collect(Collectors.toList()));
                            break;
                        }
                        case Constants.GLASS_POINT_DEFECT_OL: {
                            //统计缺陷数
                            ol.add(totalData.size());
                            //统计玻璃片数
                            olGlassNum.addAll(totalData.stream().map(ParticlePlotData::getGlassId).collect(Collectors.toList()));
                            break;
                        }
                        case Constants.GLASS_POINT_DEFECT_SB: {
                            //统计缺陷数
                            sb.add(totalData.size());
                            //统计玻璃片数
                            sbGlassNum.addAll(totalData.stream().map(ParticlePlotData::getGlassId).collect(Collectors.toList()));
                            break;
                        }
                        case Constants.GLASS_POINT_DEFECT_MB: {
                            //统计缺陷数
                            mb.add(totalData.size());
                            //统计玻璃片数
                            mbGlassNum.addAll(totalData.stream().map(ParticlePlotData::getGlassId).collect(Collectors.toList()));
                            break;
                        }
                        case Constants.GLASS_POINT_DEFECT_LB: {
                            //统计缺陷数
                            lb.add(totalData.size());
                            //统计玻璃片数
                            lbGlassNum.addAll(totalData.stream().map(ParticlePlotData::getGlassId).collect(Collectors.toList()));
                            break;
                        }
                        case Constants.GLASS_POINT_DEFECT_OLB: {
                            //统计缺陷数
                            olb.add(totalData.size());
                            //统计玻璃片数
                            olbGlassNum.addAll(totalData.stream().map(ParticlePlotData::getGlassId).collect(Collectors.toList()));
                            break;
                        }
                        default: {
                            log.error("颗粒点图没有类型--> {}", defectName);
                        }
                    }
                });
            }

            //玻璃缺陷数统计
            coldPointLineChartResp.setSDefectNum(s.stream().reduce(Integer::sum).orElse(0));
            coldPointLineChartResp.setMDefectNum(m.stream().reduce(Integer::sum).orElse(0));
            coldPointLineChartResp.setLDefectNum(l.stream().reduce(Integer::sum).orElse(0));
            coldPointLineChartResp.setOlDefectNum(ol.stream().reduce(Integer::sum).orElse(0));

            coldPointLineChartResp.setSbDefectNum(sb.stream().reduce(Integer::sum).orElse(0));
            coldPointLineChartResp.setMbDefectNum(mb.stream().reduce(Integer::sum).orElse(0));
            coldPointLineChartResp.setLbDefectNum(lb.stream().reduce(Integer::sum).orElse(0));
            coldPointLineChartResp.setOlbDefectNum(olb.stream().reduce(Integer::sum).orElse(0));

            coldPointLineChartResp.setSDefectTotalNum(coldPointLineChartResp.getSDefectNum() + coldPointLineChartResp.getSbDefectNum());
            coldPointLineChartResp.setMDefectTotalNum(coldPointLineChartResp.getMDefectNum() + coldPointLineChartResp.getMbDefectNum());
            coldPointLineChartResp.setLDefectTotalNum(coldPointLineChartResp.getLDefectNum() + coldPointLineChartResp.getLbDefectNum());
            coldPointLineChartResp.setOlDefectTotalNum(coldPointLineChartResp.getOlDefectNum() + coldPointLineChartResp.getOlbDefectNum());

            //玻璃片数统计
            coldPointLineChartResp.setSGlassNum(coldPointLineChartResp.getSDefectNum() / sGlassNum.size());
            coldPointLineChartResp.setMGlassNum(coldPointLineChartResp.getMDefectNum() / mGlassNum.size());
            coldPointLineChartResp.setLGlassNum(coldPointLineChartResp.getLDefectNum() / lGlassNum.size());
            coldPointLineChartResp.setOlGlassNum(coldPointLineChartResp.getOlDefectNum() / olGlassNum.size());

            coldPointLineChartResp.setSbGlassNum(coldPointLineChartResp.getSbDefectNum() / sbGlassNum.size());
            coldPointLineChartResp.setMbGlassNum(coldPointLineChartResp.getMbDefectNum() / mbGlassNum.size());
            coldPointLineChartResp.setLbGlassNum(coldPointLineChartResp.getLbDefectNum() / lbGlassNum.size());
            coldPointLineChartResp.setOlbGlassNum(coldPointLineChartResp.getOlbDefectNum() / olbGlassNum.size());

            coldPointLineChartResp.setSGlassTotalNum(coldPointLineChartResp.getSGlassNum() + coldPointLineChartResp.getSbGlassNum());
            coldPointLineChartResp.setMGlassTotalNum(coldPointLineChartResp.getMGlassNum() + coldPointLineChartResp.getMbGlassNum());
            coldPointLineChartResp.setLGlassTotalNum(coldPointLineChartResp.getLGlassNum() + coldPointLineChartResp.getLbGlassNum());
            coldPointLineChartResp.setOlGlassTotalNum(coldPointLineChartResp.getOlGlassNum() + coldPointLineChartResp.getOlbGlassNum());

            //玻璃总数
            coldPointLineChartResp.setGlassTotalNum(glassIds.size());
        }
        return coldPointLineChartResp;
    }


}
